Виктория:
1.Название проекта: Проект: E-commerce — Выявление профилей потребления
2.Описание проекта: Являясь аналитиком интернет-магазина товаров для дома «Пока все ещё тут», необходимо расчитать метрики и создать гипотезы на основе полученных данных, чтобы помочь магазину стать лучше.
3.Описание данных: лог сервера с данными о заказах /datasets/ecom_dataset_upd.csv
— date — дата заказа;
— customer_id — идентификатор покупателя;
— order_id — идентификатор заказа;
— product — наименование товара;
— quantity — количество товара в заказе;
— price — цена товара.
#импортирю библиотеки
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from plotly import graph_objects as go
import plotly.express as px
url = 'https://code.s3.yandex.net/datasets/'
filename = 'ecom_dataset_upd.csv'
df = pd.read_csv(url + filename)
#вывожу датафрейм
df.head()
| date | customer_id | order_id | product | quantity | price | |
|---|---|---|---|---|---|---|
| 0 | 2018100100 | ee47d746-6d2f-4d3c-9622-c31412542920 | 68477 | Комнатное растение в горшке Алое Вера, d12, h30 | 1 | 142.0 |
| 1 | 2018100100 | ee47d746-6d2f-4d3c-9622-c31412542920 | 68477 | Комнатное растение в горшке Кофе Арабика, d12,... | 1 | 194.0 |
| 2 | 2018100100 | ee47d746-6d2f-4d3c-9622-c31412542920 | 68477 | Радермахера d-12 см h-20 см | 1 | 112.0 |
| 3 | 2018100100 | ee47d746-6d2f-4d3c-9622-c31412542920 | 68477 | Хризолидокарпус Лутесценс d-9 см | 1 | 179.0 |
| 4 | 2018100100 | ee47d746-6d2f-4d3c-9622-c31412542920 | 68477 | Циперус Зумула d-12 см h-25 см | 1 | 112.0 |
#смотрю информацию по датасету
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 7474 entries, 0 to 7473 Data columns (total 6 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 date 7474 non-null int64 1 customer_id 7474 non-null object 2 order_id 7474 non-null int64 3 product 7474 non-null object 4 quantity 7474 non-null int64 5 price 7474 non-null float64 dtypes: float64(1), int64(3), object(2) memory usage: 350.5+ KB
Виктория: Названия колонок соотвествуют данным, а также изложены чётко и в нижнем регистре
#смотрю информацию по датасету
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 7474 entries, 0 to 7473 Data columns (total 6 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 date 7474 non-null int64 1 customer_id 7474 non-null object 2 order_id 7474 non-null int64 3 product 7474 non-null object 4 quantity 7474 non-null int64 5 price 7474 non-null float64 dtypes: float64(1), int64(3), object(2) memory usage: 350.5+ KB
Виктория: По коду видно, что тип данных в колонке 'date' - int64. Это значит, что необходимо привести к верному типу данный столбец
#преобразовываю столбец 'date' в тип данных datetime
df['date'] = pd.to_datetime(df['date'], format='%Y%m%d%H')
#создаю новые столбцы для выделения годов, месяцев и дней из столбца 'date'
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day'] = df['date'].dt.day
print(f'Дубликатов в датасете: {df.duplicated().sum()}')
Дубликатов в датасете: 0
Виктория: Дубликатов в датасете 0
#проверяю пропущенные значения в датасете
df.isna().sum()
date 0 customer_id 0 order_id 0 product 0 quantity 0 price 0 year 0 month 0 day 0 dtype: int64
Виктория: С пропущенными значениями также повезло - 0 пропущенных значений по всем колонкам
Виктория: С дубликатами здесь все не так однозначно, как это кажется на первый взгляд. Попробую посмотреть, если ли дубликаты без учета дат. Также посмотрю сгруппированные данные по order_id и посчитаю, сколько уникальных пользователей совершили каждый заказ.
Также проверяю даные на выбросы. Если таковые имеются, они могут сильно исказить наши результаты исследования.
#смотрю дубликаты без учёта дат
duplicates = df.duplicated(subset=['customer_id', 'order_id'])
print('Дубликатов без учёта дат:', duplicates.sum())
Дубликатов без учёта дат: 3920
Виктория: Ого! Действительно обнаружилось аж 3920 строк с дубликатами без учёта дат. Устраняем неполадку!
#удаляю дубликаты
df = df.drop_duplicates(subset=['customer_id', 'order_id'])
#группирую данные по order_id и считаю, сколько уникальных пользователей совершили каждый заказ
unique_customer = pd.DataFrame(df.groupby('order_id',
as_index=False)['customer_id'] \
.nunique() \
.sort_values(by='customer_id',
ascending=False)) \
.rename(columns={'customer_id':'cnt_unique_users'})
print(f'Всего заказов: {len(unique_customer)}')
print(f'Заказов с 1 уникальным клиентом: {len(unique_customer.query("cnt_unique_users == 1"))}')
Всего заказов: 3521 Заказов с 1 уникальным клиентом: 3492
unique_customer.head(5)
| order_id | cnt_unique_users | |
|---|---|---|
| 2610 | 72845 | 4 |
| 1914 | 71480 | 3 |
| 902 | 69485 | 3 |
| 862 | 69410 | 2 |
| 1799 | 71226 | 2 |
Виктория: В датасете оказались заказы, которые совершили несколько клиентов, что невозможно. Принято решение оставить только уникальные клиенты и заказы
#удаляю строки с дублирующими клиентами на один заказ
df = df.merge(unique_customer, on='order_id', how='left')
df = df.drop_duplicates(subset=['customer_id', 'order_id', 'product', 'cnt_unique_users'], keep='first')
#удаляю ненужный столбец
df = df.drop('cnt_unique_users', axis=1)
df = df.drop_duplicates(subset='order_id')
Виктория: Была проведена работа с дублирующими строками в датасете, а также удалены излишние данные
#анализ количества товаров в заказах
quantity = df.groupby('order_id').agg({'quantity':'sum'}).reset_index()
quantity = quantity.quantity.value_counts()
quantity.head(5)
quantity 1 2769 2 303 3 89 4 61 10 59 Name: count, dtype: int64
#строю ящик с усами для количества товаров в заказах
fig = px.box(df, y='quantity')
fig.update_layout(title='Общее количество товаров по заказам',
yaxis_title='Количество товаров',
legend_title='Количество товаров')
fig.show()
#ограничиваю ящик с усами для количества товаров в заказах до 200
fig = px.box(df, y='quantity', color_discrete_sequence=px.colors.qualitative.Prism)
fig.update_layout(title='Общее количество товаров по заказам до 200',
yaxis_title='Количество товаров',
legend_title='Количество товаров',
yaxis=dict(range=[0,200])
)
fig.show()
Виктория: По графику и по коду, можно заметить наличие выбросов в количестве товаров по заказам. Некоторые заказы, такие как заказ на 1000 товаров, выглядят аномальными. Также вызывают подозрение заказы на 300 и 334 товара. В связи с этим, было принято решение оставить только заказы, содержащие до 200 товаров.
Виктория: Смотрю внимательно на топ-5 или 10 по количеству товаров, и по ним принимаю решение.
quantity.head(10)
quantity 1 2769 2 303 3 89 4 61 10 59 5 42 6 29 15 21 30 16 7 16 Name: count, dtype: int64
Виктория: По топ-10 по количеству товаров можно сделать вывод, что люди покупают больше всего по 1 товару в заказе. Самое большее количество товаров в топ-10 - это 30 товаров в одном заказе.
Виктория: Ниже провожу сегментацию покупателей на основе их покупок методом RFM
Виктория: Ниже добавила столбец с чеком за заказ и код с учётом чека
#создаю новый столбец order_check в датасете с чеком за заказ
df['order_check'] = round(df['price'] * df['quantity'], 2)
df.head()
| date | customer_id | order_id | product | quantity | price | year | month | day | order_check | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2018-10-01 00:00:00 | ee47d746-6d2f-4d3c-9622-c31412542920 | 68477 | Комнатное растение в горшке Алое Вера, d12, h30 | 1 | 142.0 | 2018 | 10 | 1 | 142.0 |
| 1 | 2018-10-01 08:00:00 | 375e0724-f033-4c76-b579-84969cf38ee2 | 68479 | Настенная сушилка для белья Gimi Brio Super 100 | 1 | 824.0 | 2018 | 10 | 1 | 824.0 |
| 2 | 2018-10-01 08:00:00 | 6644e5b4-9934-4863-9778-aaa125207701 | 68478 | Таз пластмассовый 21,0 л круглый "Водолей" С61... | 1 | 269.0 | 2018 | 10 | 1 | 269.0 |
| 3 | 2018-10-01 09:00:00 | c971fb21-d54c-4134-938f-16b62ee86d3b | 68480 | Чехол для гладильной доски Colombo Persia Beig... | 1 | 674.0 | 2018 | 10 | 1 | 674.0 |
| 4 | 2018-10-01 11:00:00 | 161e1b98-45ba-4b4e-8236-e6e3e70f6f7c | 68483 | Вешалка для брюк металлическая с резиновым пок... | 10 | 82.0 | 2018 | 10 | 1 | 820.0 |
#рассчитываю значения Recency, Frequency и Monetary для каждого клиента
rfm_data = df.groupby('customer_id').agg({
'date': lambda x: (df['date'].max() - x.max()).days, # Recency (Последняя активность клиента)
'order_id': 'count', # Frequency (Частота)
'order_check': 'mean' # Monetary (Средний чек)
}).reset_index()
#разделяю каждый параметр на квартили
rfm_data['r_quartile'] = pd.qcut(rfm_data['date'], q=4, labels=False)
rfm_data['f_quartile'] = pd.qcut(rfm_data['order_id'], q=4, labels=False, duplicates='drop')
rfm_data['m_quartile'] = pd.qcut(rfm_data['order_check'], q=4, labels=False)
Виктория: Из проведенного анализа распределения количества заказов по каждому сегменту пользователей видно, что особенно выделяется категория клиентов из группы 213, которые совершают наибольшее количество заказов. Далее следуют категории 212 и 003. Самое малое количество заказов было сделано группами клиентов 310 и 110. Эти данные могут быть полезны для формирования маркетинговых стратегий и акций, направленных на увеличение числа заказов от клиентов из групп 310 и 110.
#cоздаю новый столбец 'rfm' и присваиваю каждому клиенту комбинацию категорий
rfm_data['rfm_category'] = rfm_data['r_quartile'].astype(int) \
+ rfm_data['f_quartile'].astype(int) \
+ rfm_data['m_quartile'].astype(int)
#укрупняю сегменты клиентов
rfm_data['rfm_segment'] = pd.qcut(rfm_data['rfm_category'],
q=4,
labels=['Lost Customer',
'Low-value customer',
'Medium value customer',
'Top Customer'])
# добавляю столбец 'rfm_segment' в исходный DataFrame
df = df.merge(rfm_data[['customer_id', 'rfm_segment']], on='customer_id', how='left')
Виктория: Ниже добавила код и визуализацию
#смотрю, количество заказов по каждой категории клиентов
rfm_segment = df.groupby('rfm_segment') \
.agg({'customer_id':'nunique'}) \
.reset_index() \
.sort_values(by='customer_id',
ascending=False) \
.rename(columns={'customer_id':'purchase_frequency'})
rfm_segment
| rfm_segment | purchase_frequency | |
|---|---|---|
| 0 | Lost Customer | 952 |
| 1 | Low-value customer | 597 |
| 2 | Medium value customer | 441 |
| 3 | Top Customer | 440 |
#визуализирую распределение категории клиентов по количеству заказов в виде столбчатой диаграммы
fig = px.bar(rfm_segment,
x='rfm_segment',
y='purchase_frequency',
text='purchase_frequency',
color_discrete_sequence=px.colors.qualitative.Pastel)
fig.update_layout(title='Распределение категории клиентов по количеству заказов',
xaxis_title='Категория клиента',
yaxis_title='Количество заказов')
fig.show()
Виктория: ВЫВОД
Исходя из анализа данных о сегментах клиентов, можно сделать следующие выводы:
Наибольшую группу клиентов составляют "Потерянные клиенты" (Lost Customer) - 952 клиента. Это может указывать на то, что эти клиенты не совершали покупок в течение определенного периода времени и требуют дополнительных усилий для их возвращения и удержания.
Следующий по величине сегмент клиентов - "Клиенты с низкой стоимостью" (Low-value customer) - 597. Это означает, что эти клиенты делают относительно небольшое количество покупок и приносят меньший доход компании. Важно разработать стратегию для стимулирования их активности и увеличения стоимости покупок.
Сегмент "Клиенты средней стоимости" (Medium value customer) составляют третью по величине группу клиентов с показателем 440. Они делают меньше покупок и приносят меньший доход, чем "Топ-клиенты", но больше, чем "Клиенты с низкой стоимостью". Рекомендуется разработать стратегию для стимулирования их активности и увеличения стоимости покупок.
"Топ-клиенты" (Top Customer) являются наименьшей группой - 438 пользователя. Эти клиенты являются самыми активными и приносят наибольший доход компании. Стратегия должна быть направлена на удержание и дальнейшее развитие отношений с этой группой клиентов.
#добавляю новый столбец 'product_name'
df['product_name'] = df['product'].str.split().str[:2].str.join(' ')
df['product_name'] = df['product_name'].str.lower()
#ИСПРАВЛЕННЫЙ КОД
#расформировываю категорию "Другое" по ключевым словам
df.loc[df['product_name'].str.contains('котел|светильник|измерительный|фоторамка|этажерка|электроштопор|простынь|фиттония|орехоколка|электрический|миксер|радиаторный|картофелемялка|утюг|пылесос|окномойка|чайник|термокружка|весы|tepмокружка|измельчитель'), 'product_name_category'] = 'Техника и аксессуары'
df.loc[df['product_name'].str.contains('кодонанта|суккулент|кампанула|иссоп|аспарагус|карниз|артемизия|антижир|мантоварка|бархатцы|алиссум|подсолнечник|пуансетия|гиностемма|ель|защитный экран|альбука спиралис|розмарин d-9|гимнокалициум микс|папоротник|осина|лавр|эпипремнум|флокс|аквилегия|душица|муррайя|джункус|драцена|нефролепис'), 'product_name_category'] = 'Растения'
df.loc[df['product_name'].str.contains('шприц|лоток|сахарница|скалка|пакет|тортница|скребок|венчик|сито|рыбочистка|ковш|противень|блюдце|блюдо|крышка|хлебница|кастрюля|масленка|салфетка|набор|тарелка|ложка|нож|вилка|сковорода|салатник|сотейник|скатерть|кувшин|банка|контейнер|бидон|кружка|термос|овощеварка|миска|овощечистка|бульонница|толкушка|соковарка|форма'), 'product_name_category'] = 'Посуда'
df.loc[df['product_name'].str.contains('обувница|ключница|термометр|веник|коробка|урна|комод|детский|для|коврик|крючок|корзина|доска|полка|полки|ящик|кашпо|ковер|стяжка|сиденье|терка|подголовник bacchetta|складная картонная|модульная стеклянная|подушка декоративная|корзинка|уголок|ковёр придверный'), 'product_name_category'] = 'Мебель'
df.loc[df['product_name'].str.contains('маска|махровый|гладильная|ведро|ванна|петля|вантуз|паста|мыльница|таз|сушилка|щетка|корыто|полотенце|швабра|перчатки|тряпкодержатель'), 'product_name_category'] = 'Ванная'
df.loc[df['product_name'].str.contains('овсянница|травы|розмарин|томат|кумкват|укроп|лук|виноград|капуста|кориандр|дыня|клубника|клен|чабер|рассада|помидор|базилик|петрушка|тимьян'), 'product_name_category'] = 'Растения'
df.loc[df['product_name'].str.contains('тележка|сумка'), 'product_name_category'] = 'Сумки и тележки'
df.loc[df['product_name'].str.contains('ткань|подушка|наматрасник|наволочка|наматрацник|пододеяльник|покрывало|одеяло|комплект|плед|штора|чехол|халат|вешалки|комплект|плечики|вешалка|подкладка|подрукавник|плед|простыня|штора|покрывало|одеяло|плед'), 'product_name_category'] = 'Спальня'
df.loc[df['product_name'].str.contains('шеффлера|литопс|пахира|молодило|диффенбахия|травянистая|хризолидокарпус|крассула|алоэ|аптения|эхеверия|фатсия|вербейник|комнатное|фал|кофе|хлорофитум|мята|цветок|дендробиум|кипарисовик|растение|дерево|эвкалипт|эхинокактус|циперус|арбуз|табак|соланум|сциндапсус|каланхое|замиокулькас|нолина|кореопсис|хамедорея|зверобой'), 'product_name_category'] = 'Растения'
df.loc[df['product_name'].str.contains('земляника|огурец|календула|гортензия|пеперомия|виола|крокусы|гиацинт|метельчатый|метельчатая|хризантема|ранункулус|калла|фуксия|спатифиллум|гайлардия|гипсофила|котовник|калатея|космея|амариллис|гербера|адиантум|незабудка|примула|лантана|мимоза|вербена|георгина|целозия|физостегия|пиретрум|цинния|змееголовник|цинния|энотера|львиный|тюльпан|колокольчик|импатиенс|скиммия|мускари|синнингия|гардения|гвоздика|вероника|пеларгония|петуния|калибрахоа|роза|тагетис|герань|бакопа|азалия|афеляндра|антуриум|бальзамин|фиалка|\пуансеттия|бегония|декабрист|пуансеттия|настурция|мединилла|цикламен|лаванда'), 'product_name_category'] = 'Цветы'
df.loc[df['product_name'].str.contains('камнеломка|фикус|муляж|искусственная|искусственный|композиция'), 'product_name_category'] = 'Оформление дома'
df.loc[df['product_name'].str.contains('пьезозажигалка|сверло|холодная сварка|многофункциональный инструмент|шило|совок|толкушка|соковарка|половник|ёрш|мерный стакан|линейка, длина|шпингалет|кисточка|решетка|рассекатель|шнур|хром|ручка|петля-стрела|веревка|сметка|штангенциркуль|мирт|шпагат|стремянка|насадка|завертка|стремянки'), 'product_name_category'] = 'Инструменты'
df.loc[df['product_name'].str.contains('защитная соль|нетканые салфетки|салфетница металлическая|гипоаллергенный|отбеливатель|средство|мыло'), 'product_name_category'] = 'Бытовая химия'
#смотрю, на какие категории товаров поделились данные из датасета
product_name_category = df.groupby('product_name_category') \
.agg({'order_id':'count'}) \
.reset_index() \
.sort_values(by='order_id',
ascending=False) \
.rename(columns={'order_id':'cnt'})
product_name_category
| product_name_category | cnt | |
|---|---|---|
| 10 | Цветы | 624 |
| 1 | Ванная | 589 |
| 6 | Растения | 428 |
| 3 | Мебель | 422 |
| 8 | Сумки и тележки | 374 |
| 5 | Посуда | 336 |
| 7 | Спальня | 295 |
| 4 | Оформление дома | 234 |
| 2 | Инструменты | 135 |
| 9 | Техника и аксессуары | 61 |
| 0 | Бытовая химия | 23 |
#визуализирую распределение категории прдуктов по количеству заказов в виде столбчатой диаграммы
fig = px.bar(product_name_category, x='product_name_category',
y='cnt',
text='cnt',
color_discrete_sequence=px.colors.qualitative.Prism)
fig.update_layout(title='Распределение категории продуктов по количеству заказов',
xaxis_title='Категория товара',
yaxis_title='Количество заказов')
fig.show()
Виктория: Исходя из анализа данных о распределении категории продуктов по количеству заказов, можно сделать следующие выводы:
Самой популярной товарной группой являются "Цветы" с общим количеством заказов равным 624. Это указывает на высокий спрос на цветочные товары и их значимость для клиентов.
"Ванная" занимает второе место по популярности с количеством заказов равным 588. Это говорит о том, что товары для ванной комнаты также являются востребованными среди клиентов.
"Растения" и "Мебель" занимают третье и четвертое места соответственно с количеством заказов 428 и 422. Эти товарные группы также пользуются значительным спросом среди клиентов.
"Сумки и тележки" и "Посуда" занимают пятую и шестую позиции с количеством заказов 374 и 336 соответственно.
"Спальня", "Оформление дома", "Инструменты", "Техника и аксессуары" и "Бытовая химия" занимают меньшие позиции по популярности с количеством заказов от 294 до 23. Это может указывать на более низкий спрос на эти товарные группы или на их специфичность.
#перевожу тип данных столбца rfm_segment из category в object
df['rfm_segment'] = df['rfm_segment'].astype('object')
#строю таблицу для категорий товаров и категорий клиентов
grouped_by_categories = df.groupby(['rfm_segment', 'product_name_category'],
as_index=False).agg({'order_id':'count'}).rename(columns={'order_id':'cnt'})
grouped_by_categories.head()
| rfm_segment | product_name_category | cnt | |
|---|---|---|---|
| 0 | Lost Customer | Бытовая химия | 11 |
| 1 | Lost Customer | Ванная | 194 |
| 2 | Lost Customer | Инструменты | 42 |
| 3 | Lost Customer | Мебель | 172 |
| 4 | Lost Customer | Оформление дома | 100 |
#визуализирую количество заказов по категориям клиентов и товаров
fig = px.bar(grouped_by_categories.sort_values(by='cnt', ascending=False),
x='cnt',
y='rfm_segment',
color='product_name_category',
orientation='h',
color_discrete_sequence=px.colors.qualitative.Prism,
title='Количество заказов по категориям клиентов и товаров')
fig.update_layout(xaxis_title='Количество заказов',
yaxis_title='Категории клиентов',
legend_title='Категории товаров')
fig.show()
Виктория: Исходя из проведенного анализа данных о распределении предпочтений категорий продуктов по категориям клиентов, можно сделать следующие выводы:
У "Потерянных клиентов" (Lost Customer) и "Клиентов с низкой стоимостью" (Low-value customer) наиболее популярной категорией товаров являются цветы. Это может указывать на то, что эти клиенты склонны приобретать товары для украшения и оформления своего пространства.
У "Топ-клиентов" (Top Customer) и "Клиентов средней стоимости" (Medium Value Customer) на первом месте предпочтений находятся предметы для ванной комнаты. Это может указывать на то, что эти клиенты больше интересуются товарами, связанными с комфортом и уходом за собой.
На вторых и третьих позициях продуктов у "Потерянных клиентов" (Lost Customer) идут растения и товары для ванной комнаты, у "Клиентов с низкой стоимостью" (Low-value customer) - товары для ванной комнаты и мебель, у "Топ-клиентов" (Top Customer) - сумки и тележки, а также мебель на третьем месте. У "Клиентов средней стоимости" (Medium Value Customer) на втором месте находятся цветы, а на третьем - мебель.
Таким образом, можно сделать вывод, что предпочтения клиентов в различных категориях продуктов могут быть связаны с их статусом, финансами, потребностями и интересами.
#строю гистограмму по годам
df['year'].value_counts().plot(kind='bar', grid=True, color='Lavender')
#настраиваю оси и заголовки
plt.xlabel('Год')
plt.ylabel('Количество заказов')
plt.title('Гистограмма количества заказов по годам')
plt.xticks(rotation=45)
#отображаю гистограмму
plt.show()
Виктория: При анализе количества заказов по годам обнаружилось, что заказов с каждым годом становится всё меньше, а с 2018 года идёт спад по продажам.
#добавлюя столбец с сезоном для дальнейшего анализа
df['season'] = df['month'].apply(lambda x: 'winter' if x in [12, 1, 2] \
else 'spring' if x in [3, 4, 5] \
else 'summer' if x in [6, 7, 8] \
else 'autumn')
#добавлюя таблицу с сезонами, категориями клиентов и товаров для дальнейшего анализа
grouped_data = df.groupby(['rfm_segment', 'season', 'product_name_category']).size().reset_index(name='count')
grouped_data = grouped_data.sort_values('season', key=lambda x: x.map({'winter': 1, 'spring': 2, 'summer': 3, 'autumn': 4}))
grouped_data
| rfm_segment | season | product_name_category | count | |
|---|---|---|---|---|
| 82 | Low-value customer | winter | Сумки и тележки | 30 |
| 84 | Low-value customer | winter | Цветы | 53 |
| 83 | Low-value customer | winter | Техника и аксессуары | 4 |
| 164 | Top Customer | winter | Техника и аксессуары | 7 |
| 81 | Low-value customer | winter | Спальня | 18 |
| ... | ... | ... | ... | ... |
| 134 | Top Customer | autumn | Сумки и тележки | 39 |
| 135 | Top Customer | autumn | Техника и аксессуары | 8 |
| 51 | Low-value customer | autumn | Сумки и тележки | 40 |
| 49 | Low-value customer | autumn | Растения | 30 |
| 0 | Lost Customer | autumn | Бытовая химия | 4 |
166 rows × 4 columns
#строю график для сегмента lost_customer
lost_customer = grouped_data[grouped_data['rfm_segment']=='Lost Customer']
fig = px.line(lost_customer,
x='season',
y='count',
color='product_name_category',
title='Анализ по сезонам категорий товаров для пользователей сегмента "Lost Customer"')
fig.update_layout(xaxis_title='Сезон',
yaxis_title='Количество заказов',
legend_title='Категории товаров')
fig.show()
Виктория: Исходя из проведенного анализа данных о сезонности категорий товаров по сегменту "Потерянных клиентов" (Lost Customer), можно сделать следующие выводы:
Сегмент "Потерянных клиентов" проявляет наибольший интерес по количеству заказов в категориях "Цветы", "Растения" и товаров для ванной. Это является потенциальной возможностью для повышения спроса на эти товары.
В категории цветы наблюдается сезонность. Интерес к этой категории возрастает весной, вероятно, в связи с праздниками. Затем к лету происходит спад, но в осенние месяцы интерес снова возрастает, возможно, из-за предстоящей школы, дня знаний и дня учителя.
Интерес к растениям увеличивается с лета до осени, но зимой и весной он падает. Это может быть связано с изменением климата и сезонными особенностями ухода за растениями.
Категории товаров для ванны, спальни, мебели и посуды также проявляют сезонность, но в обратном направлении. Интерес к ним падает весной. Возможно, это связано с периодом уборки и обновления интерьера после зимы.
В категории бытовой химии не наблюдается явной сезонности. Это говорит о том, что бытовая химия является неотъемлемой частью повседневной жизни людей и покупается ими в течение всего года. Однако, спрос на нее может быть невысоким, что открывает возможности для увеличения спроса на этот сегмент.
Оформление дома и товары для спальни испытывают снижение интереса летом. Вероятно, это связано с тем, что в это время люди предпочитают проводить время на даче или отдыхать на открытом воздухе.
#строю график для сегмента low_value_customer
low_value_customer = grouped_data[grouped_data['rfm_segment']=='Low-value customer']
fig = px.line(low_value_customer,
x='season',
y='count',
color='product_name_category',
title='Анализ по сезонам категорий товаров для пользователей сегмента "Low-value Customer"')
fig.update_layout(xaxis_title='Сезон',
yaxis_title='Количество заказов',
legend_title='Категории товаров')
fig.show()
Виктория: Исходя из проведенного анализа данных о сезонности категорий товаров по сегменту "Клиентов с низкой стоимостью" (Low-value customer), можно сделать следующие выводы:
Цветы, растения и товары для ванной являются наиболее популярными категориями среди "Клиентов с низкой стоимостью" (Low-value customer). Эти товары имеют наибольшее количество заказов по сравнению с другими категориями.
Растет интерес к растениям и оформлению дома к весне, что может быть связано с началом сезона садоводства и желанием клиентов обновить интерьер своего дома.
К лету спрос на инструменты, растения и цветы снижается. Возможно, это связано с тем, что в это время "Клиентов с низкой стоимостью" (Low-value customer) стоимостью предпочитают не тратить деньги на товары с высокой стоимостью.
Продажи товаров для ванной падают весной, но затем начинают расти в летние и осенние месяцы. Вероятно, это связано с сезонными изменениями в потребностях клиентов.
Техника и аксессуары не имеют явно выраженной сезонности и покупаются "Клиентов с низкой стоимостью" (Low-value customer) на протяжении всего года. Аналогично, бытовая химия также пользуется стабильным спросом.
grouped_data = grouped_data.sort_values('season', key=lambda x: x.map({'winter': 1, 'spring': 2, 'summer': 3, 'autumn': 4}))
#строю график для сегмента medium_value_customer
medium_value_customer = grouped_data[grouped_data['rfm_segment']=='Medium value customer']
fig = px.line(medium_value_customer,
x='season',
y='count',
color='product_name_category',
title='Анализ по сезонам категорий товаров для пользователей сегмента "Medium value Customer"')
fig.update_layout(xaxis_title='Сезон',
yaxis_title='Количество заказов',
legend_title='Категории товаров')
fig.show()
Виктория: Исходя из проведенного анализа данных о сезонности категорий товаров по сегменту "Клиентов средней стоимости" (Medium Value Customer), можно сделать следующие выводы:
Клиенты средней стоимости проявляют интерес и рост спроса на товары категории "Сумки и тележки". Это свидетельствует о том, что эти клиенты ценят комфорт и удобство при покупках. Пик спроса на сумки и тележки приходится на весну.
В течение всего года наблюдается стабильный спрос на товары для ванной. Это говорит о том, что клиенты средней стоимости регулярно приобретают такие товары и не зависят от сезонных изменений.
Не выявлено сезонности в спросе на бытовую химию. Это может означать, что клиенты средней стоимости покупают такие товары постоянно, независимо от времени года.
Категории "Цветы" и "Посуда" имеют пик спроса весной, а спад летом. Это может быть связано с тем, что клиенты средней стоимости активнее покупают цветы и посуду в период весенних праздников и сезона отпусков.
Категория "Мебель" имеет резкий спад спроса весной, но затем наблюдается резкий рост от весны до осени. Это может указывать на то, что клиенты средней стоимости предпочитают покупать мебель в более теплые месяцы года.
Категории "Инструменты" набирают спрос от весны до осени.
#строю график для сегмента top_customer
top_customer = grouped_data[grouped_data['rfm_segment']=='Top Customer']
fig = px.line(top_customer,
x='season',
y='count',
color='product_name_category',
title='Анализ по сезонам категорий товаров для пользователей сегмента "Top Customer"')
fig.update_layout(xaxis_title='Сезон',
yaxis_title='Количество заказов',
legend_title='Категории товаров')
fig.show()
Виктория: Исходя из проведенного анализа данных о сезонности категорий товаров по сегменту "Топ-клиентов" (Top Customer), можно сделать следующие выводы:
Все категории товаров проявляют сезонность от лета до осени. Вероятно, это связано с тем, что летом у клиентов появляется больше времени на приобретение товаров для ванны, сумок и тележек, спальни, посуды, мебели и других категорий. Однако, интерес к этим товарам падает от зимы до весны и далее до лета.
Отдельно стоит отметить категорию инструменты, где наблюдается интересный пик весной.
Категории товаров, связанные с оформлением дома, техникой, растениями и цветами также имеют схожую тенденцию: спад с зимы до лета и рост от лета до осени.
Виктория:
Для проверки гипотезы о равенстве средних частот покупок и среднего чека между различными сегментами клиентов я подкорректировала тест и использовала тест Манна-Уитни для независимых выборок (если p-значение теста Шапиро-Уилка больше alpha, применяла непараметрический тест Манна-Уитни, в обратном случае t-тест). Этот тест является непараметрическим и не требует предположений о нормальности распределения данных. Однако перед применением теста я сначала всё-таки проверила нормальность распределения частот покупок в каждом сегменте и среднего чека с помощью теста Шапиро-Уилка.
df = df.merge(rfm_segment, on='rfm_segment', how='left')
df.head(2)
| date | customer_id | order_id | product | quantity | price | year | month | day | order_check | rfm_segment | product_name | product_name_category | season | purchase_frequency | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2018-10-01 00:00:00 | ee47d746-6d2f-4d3c-9622-c31412542920 | 68477 | Комнатное растение в горшке Алое Вера, d12, h30 | 1 | 142.0 | 2018 | 10 | 1 | 142.0 | Low-value customer | комнатное растение | Растения | autumn | 597 |
| 1 | 2018-10-01 08:00:00 | 375e0724-f033-4c76-b579-84969cf38ee2 | 68479 | Настенная сушилка для белья Gimi Brio Super 100 | 1 | 824.0 | 2018 | 10 | 1 | 824.0 | Top Customer | настенная сушилка | Ванная | autumn | 440 |
pip install scipy
Requirement already satisfied: scipy in c:\users\79261\appdata\local\programs\python\python311\lib\site-packages (1.12.0)Note: you may need to restart the kernel to use updated packages.
[notice] A new release of pip is available: 23.2.1 -> 24.0 [notice] To update, run: python.exe -m pip install --upgrade pip
Requirement already satisfied: numpy<1.29.0,>=1.22.4 in c:\users\79261\appdata\local\programs\python\python311\lib\site-packages (from scipy) (1.25.2)
import scipy.stats as st
#задаю уровень значимости alpha
alpha = 0.05
#создаю список rfm_segments, содержащий все возможные значения столбца 'rfm' в датасете
rfm_segments = ['Medium value customer', 'Top Customer', 'Lost Customer', 'Low-value customer']
#создаю пустой список p_values, в который буду добавлять значения p-значений
p_values = []
#для каждого сегмента из списка rfm_segments выполняю следующие действия:
for segment in rfm_segments:
segment_frequency = df[df['rfm_segment'] == segment]['purchase_frequency']
#выделяю данные о частоте покупок для текущего сегмента
other_frequency = df[df['rfm_segment'] != segment]['purchase_frequency']
#выделяю данные о частоте покупок для всех остальных сегментов
#проверяю нормальность распределения с помощью теста Шапиро-Уилка
shapiro_test = st.shapiro(segment_frequency)
#если p-значение теста Шапиро-Уилка больше alpha, применяю непараметрический тест Манна-Уитни
if shapiro_test.pvalue > alpha:
results = st.mannwhitneyu(segment_frequency, other_frequency) #применяю тест Манна-Уитни для независимых выборок
else:
results = st.ttest_ind(segment_frequency, other_frequency) #применяю t-тест для независимых выборок
p_value = results.pvalue #извлекаю значение p-значения из результатов теста
p_values.append(p_value) #добавляю p_value в список p_values
#устанавливаю уровень статистической значимости исходя из множественной проверки гипотез
alpha_adjusted = alpha / len(rfm_segments)
#для каждого сегмента и его соответствующего p-значения из списка rfm_segments и p_values выполняю следующие действия:
#если p-значение меньше уровня статистической значимости, выводится сообщение о том, что нулевая гипотеза отвергается
#в противном случае выводится сообщение о том, что нет оснований отвергать нулевую гипотезу
for i, segment in enumerate(rfm_segments):
if p_values[i] < alpha_adjusted:
print(f'Отвергаем нулевую гипотезу для сегмента {segment}')
else:
print(f'Нет оснований отвергать нулевую гипотезу для сегмента {segment}')
Отвергаем нулевую гипотезу для сегмента Medium value customer Отвергаем нулевую гипотезу для сегмента Top Customer Отвергаем нулевую гипотезу для сегмента Lost Customer Отвергаем нулевую гипотезу для сегмента Low-value customer
C:\Users\79261\AppData\Local\Temp\ipykernel_13584\3952553517.py:18: UserWarning: scipy.stats.shapiro: Input data has range zero. The results may not be accurate.
Виктория: Вывод: отвергаем нулевую гипотезу для всех клиентов. Исходя из результатов анализа, можно сделать вывод, что есть статистически значимые различия в частоте покупок у покупателей из разных сегментов. Это означает, что сегменты покупателей имеют различную активность в покупках.
#смотрю, какой средний чек по заказам делала каждая категория клиентов
avg_check = df.groupby('rfm_segment') \
.agg({'price':'mean'}) \
.round(2) \
.reset_index() \
.rename(columns={'price':'avg_check'}) \
.sort_values(by='avg_check',
ascending=False)
avg_check
| rfm_segment | avg_check | |
|---|---|---|
| 3 | Top Customer | 1196.74 |
| 2 | Medium value customer | 1043.38 |
| 1 | Low-value customer | 949.11 |
| 0 | Lost Customer | 332.90 |
df = df.merge(avg_check, on='rfm_segment', how='left')
df.head(2)
| date | customer_id | order_id | product | quantity | price | year | month | day | order_check | rfm_segment | product_name | product_name_category | season | purchase_frequency | avg_check | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2018-10-01 00:00:00 | ee47d746-6d2f-4d3c-9622-c31412542920 | 68477 | Комнатное растение в горшке Алое Вера, d12, h30 | 1 | 142.0 | 2018 | 10 | 1 | 142.0 | Low-value customer | комнатное растение | Растения | autumn | 597 | 949.11 |
| 1 | 2018-10-01 08:00:00 | 375e0724-f033-4c76-b579-84969cf38ee2 | 68479 | Настенная сушилка для белья Gimi Brio Super 100 | 1 | 824.0 | 2018 | 10 | 1 | 824.0 | Top Customer | настенная сушилка | Ванная | autumn | 440 | 1196.74 |
#задаю уровень значимости alpha
alpha = 0.05
#создаю список rfm_segments, содержащий все возможные значения столбца 'rfm' в датасете
rfm_segments = ['Medium value customer', 'Top Customer', 'Lost Customer', 'Low-value customer']
#создаю пустой список p_values, в который буду добавлять значения p-значений
p_values = []
#для каждого сегмента из списка rfm_segments выполняю следующие действия:
for segment in rfm_segments:
segment_frequency = df[df['rfm_segment'] == segment]['avg_check']
#выделяю данные о среднем чеке для текущего сегмента
other_frequency = df[df['rfm_segment'] != segment]['avg_check']
#выделяю данные о среднем чеке для всех остальных сегментов
#проверяю нормальность распределения с помощью теста Шапиро-Уилка
shapiro_test = st.shapiro(segment_frequency)
#если p-значение теста Шапиро-Уилка больше alpha, применяю непараметрический тест Манна-Уитни
if shapiro_test.pvalue > alpha:
results = st.mannwhitneyu(segment_frequency, other_frequency) #применяю тест Манна-Уитни для независимых выборок
else:
results = st.ttest_ind(segment_frequency, other_frequency) #применяю t-тест для независимых выборок
p_value = results.pvalue #извлекаю значение p-значения из результатов теста
p_values.append(p_value) #добавляю p_value в список p_values
#устанавливаю уровень статистической значимости исходя из множественной проверки гипотез
alpha_adjusted = alpha / len(rfm_segments)
#для каждого сегмента и его соответствующего p-значения из списка rfm_segments и p_values выполняю следующие действия:
#если p-значение меньше уровня статистической значимости, выводится сообщение о том, что нулевая гипотеза отвергается
#в противном случае выводится сообщение о том, что нет оснований отвергать нулевую гипотезу
for i, segment in enumerate(rfm_segments):
if p_values[i] < alpha_adjusted:
print(f'Отвергаем нулевую гипотезу для сегмента {segment}')
else:
print(f'Нет оснований отвергать нулевую гипотезу для сегмента {segment}')
Отвергаем нулевую гипотезу для сегмента Medium value customer Отвергаем нулевую гипотезу для сегмента Top Customer Отвергаем нулевую гипотезу для сегмента Lost Customer Отвергаем нулевую гипотезу для сегмента Low-value customer
C:\Users\79261\AppData\Local\Temp\ipykernel_13584\189160445.py:18: UserWarning: scipy.stats.shapiro: Input data has range zero. The results may not be accurate.
Виктория: Вывод: отвергаем нулевую гипотезу для всех клиентов. В результате проведенного анализа можно сделать вывод о наличии различий в среднем чеке между покупателями из разных сегментов. Нулевая гипотеза об отсутствии различий была отвергнута для всех четырех сегментов: Medium value customer, Top Customer, Lost Customer и Low-value customer. Это означает, что средний чек в этих сегментах значительно различается.
Виктория: Исходя из полученных данных, можно сделать следующие рекомендации для каждого сегмента клиентов:
1.Описание: Из анализа выявлено, что наибольшую группу клиентов составляют "Потерянные клиенты" (Lost Customer), у котоорых наблюдается низкая средняя сумма покупки. Это может указывать на то, что данные сегменты клиентов склонны приобретать товары с низкой ценой. Анализируя данные о частоте покупок данной категории клиентов стоит отметить, что большинство клиентов (952 чел.) относятся к категории "Потерянные клиенты". Это означает, что магазин очень часто приходят клиенты, но долго не задерживаются и по каким-то причинам перестают покупать, так что надо принять меры для их возвращения и удержания.
2.Предпочтительные категории: Для этого сегмента клиентов наиболее популярными категориями товаров являются цветы. Это указывает на то, что эти клиенты склонны приобретать товары для украшения и оформления своего пространства. Кроме того, у "Потерянных клиентов" (Lost Customer) также популярны растения и товары для ванной комнаты. Для сегмента "Потерянных клиентов" (Lost Customer) наблюдается резкий рост спроса на эти категории товаров в начале 2019 года, однако после этого спрос снижается. Также стоит обратить внимание на категории товаров "Оформление дома" и мебель, которые вызывают интерес у "Потерянных клиентов" (Lost Customer), хотя в меньшей степени.
3.Рекомендация: Необходимо рассмотреть возможность увеличения рекламных предложений в категориях "Цветы", "Растения" и товары для ванной. Эти категории товаров пользуются наибольшим интересом у этого сегмента клиентов. Регулярная рассылка акций и скидок на эти товары может привлечь внимание и повысить спрос. Также стоит учесть сезонность в категории цветы. Нужно увеличить рекламные предложения весной, в преддверии праздников, а также осенью, связанной с началом учебного года. Это поможет увеличить продажи в эти периоды. Повышенный интерес к растениям летом и осенью может быть использован для проведения акций и специальных предложений, чтобы стимулировать покупку.Можно обратить внимание на категорию бытовой химии. Возможно, спрос на этот сегмент не высок, поэтому рекомендуется проводить акции и предложения, чтобы привлечь внимание к этой категории и увеличить продажи. Сезонность в категории оформления дома и товаров для спальни: в летние месяцы, когда интерес к этим товарам снижается, можно сконцентрироваться на других категориях или предложить специальные акции, связанные с отпуском и отдыхом на открытом воздухе.
1.Описание: Второй по величине сегмент клиентов - сегмент "Клиенты с низкой стоимостью" (Low-value customer, 597 клиентов). Из предоставленных данных видно, что средний чек клиента зависит от его сегмента. Низкое значение среднего чека у клиентов с низкой ценностью (877.16), что свидетельствует о низкой чеке покупок клиентов. Однако данные клиенты часто покупают и являются вторым сегментом по частоте покупок, что означает, что их можно стимулировать покупать ещё чаще.
2.Предпочтительные категории: Наиболее популярной категорией товаров в этом сегменте являются цветы, указывая на склонность клиентов к приобретению товаров для украшения и оформления своего пространства. Товары для ванной комнаты и растения также занимают вторые и третьи позиции продуктов в этом сегменте.
3.Рекомендация: предлагается следующая стратегия для сегмента клиентов с низкой стоимостью: рассылать рекламные предложения о цветах, растениях и товарах для ванной на протяжении всего года, так как эти категории товаров наиболее популярны среди данного сегмента клиентов. Особое внимание следует уделить летним и осенним месяцам, когда спрос на эти товары повышается. Весной, когда спрос на инструменты, растения и цветы снижается, можно сосредоточиться на других категориях товаров, которые пользуются стабильным спросом, например, на технику и аксессуары или бытовую химию. Можно проводить специальные акции и предложения в периоды повышенного спроса на растения и оформление дома, например, весной и осенью. Это может стимулировать клиентов с низкой стоимостью к увеличению количества приобретаемых товаров.
1.Описание: Сегмент "Клиенты средней стоимости" занимают третью по величине группу клиентов с показателем покупательной активности, равным 440 клиента, но играет не менее важную роль и является перспективным сегментом покупателей, на который стоит обратить внимание. Клиенты со средним значением имеют средний чек в размере 1054.15, что может указывать на их умеренную активность и лояльность.
2.Предпочтительные категории: Предметы для ванной комнаты занимают первое место в предпочтениях этого сегмента, что свидетельствует о большом интересе клиентов к товарам, связанным с комфортом и уходом за собой. Первые три позиции продуктов в сегменте "Клиенты средней стоимости" занимают цветы и сумки и тележки.
3.Рекомендация: Рекомендуется акцентировать внимание на категории "Сумки и тележки" весной, так как именно в этот период проявляется наибольший интерес к товарам этой категории. Стоит предлагать специальные предложения, скидки или бонусы при покупке сумок и тележек весной. Исходя из стабильного спроса на товары для ванной в течение всего года, рекомендуется проводить регулярные рекламные кампании для этой категории товаров. Можно подчеркнуть их универсальность и пользу в повседневной жизни. В связи с отсутствием сезонности в спросе на бытовую химию, стоит предлагать продукты этой категории в рекламных предложениях также круглогодично. Можно, например, вводить программы лояльности или скидки при покупке определенного объема товаров. Цветы и посуда: усилия на рекламе весной, особенно в период весенних праздников. Инструменты (весна-осень): с учетом набора спроса на инструменты от весны до осени, рекомендуется акцентировать внимание на этой категории товаров в этот период. А, учитывая резкий спад спроса на мебель весной, но рост летом и осенью, рекомендуется запускать рекламные кампании и акции на мебель в более теплые месяцы. Можно также предоставлять специальные предложения для стимулирования покупок в период весенне-летнего подъема.
1.Описание: "Топ-клиенты" занимают третью по величине группу клиентов с показателем покупательной активности имеет наименьшую покупательную активность с показателем, равным 438 клиентов. Топ-клиенты имеют самый высокий средний чек в размере 1389.38, что говорит о высокой степени лояльности и активности таких клиентов. В целом, можно уделить больше внимания топ-клиентам, так как они приносят наибольший доход. Предоставить им дополнительные привилегии, скидки или бонусы, чтобы поддерживать их лояльность.
2.Предпочтительные категории: Оформление для дома занимают первое место в предпочтениях этого сегмента, что указывает на интерес клиентов к товарам, связанным с комфортом и уходом за своим жильем. Первые три позиции продуктов в сегменте "Топ-клиентов" занимают предметы для спальни, сумки и тележки, а также посуда.
3.Рекомендация: можно рассылать рекламные предложения по категориям товаров, которые проявляют сезонность от лета до осени. Это включает товары для ванны, сумки и тележки, спальни, посуду, мебель и другие подобные категории. Например, в начале лета можно предложить клиентам акции на товары для пляжа, а в осенний период - на предметы для украшения дома к праздникам. Также стоит уделить особое внимание категории инструментов, так как наблюдается пик интереса весной. В это время можно проводить специальные акции и предложения на инструменты для сада и дачи, например. Начиная с лета и до осени, клиенты проявляют больший интерес к товарам, связанным с оформлением дома, техникой, растениями и цветами. В это время можно предлагать клиентам специальные скидки, акции или бонусы при покупке на эти категории.
Виктория:
Презентация: https://drive.google.com/file/d/16CN0_bTMyf1Lr5Jss5yPERNTRoOGYl6q/view?usp=sharing
#ниже доп.инструменты
df
# Укажите путь и имя файла, в который вы хотите сохранить данные
save_path = 'C:/Users/79261/Downloads/tableau_project.csv'
df.to_csv(save_path, index=False)